// DlgChangeLibrary.cpp : implementation file
//

#include "stdafx.h"
#include "Celsus.h"
#include "DlgChangeLibrary.h"


// CDlgChangeLibrary dialog

IMPLEMENT_DYNAMIC(CDlgChangeLibrary, CDialog)

CDlgChangeLibrary::CDlgChangeLibrary(CWnd* pParent /*=NULL*/)
	: CDialog(CDlgChangeLibrary::IDD, pParent)
	, m_bIndicator(FALSE)
	, m_bRetainStatus(FALSE)
{
	m_nType = TYPE_CHANGE;
	m_nStaffID = -1;
	m_nCurrentLibrary = -1;
	m_nNewLibrary = -1;
	m_nSelectedLibrary = -1;
	m_nCurrentSort = -1;
	m_bSortAscending = FALSE;
}

CDlgChangeLibrary::~CDlgChangeLibrary()
{
}

void CDlgChangeLibrary::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Check(pDX, IDC_CHECK_INDICATOR, m_bIndicator);
	DDX_Check(pDX, IDC_CHECK_RETAIN_STATUS, m_bRetainStatus);
	DDX_Control(pDX, IDC_LIST_LIBRARIES, m_ctrlLibraries);
}


BEGIN_MESSAGE_MAP(CDlgChangeLibrary, CDialog)
	ON_NOTIFY(LVN_ITEMCHANGED, IDC_LIST_LIBRARIES, &CDlgChangeLibrary::OnLvnItemchangedListLibraries)
	ON_NOTIFY(LVN_GETDISPINFO, IDC_LIST_LIBRARIES, &CDlgChangeLibrary::OnLvnGetdispinfoListLibraries)
	ON_NOTIFY(NM_CUSTOMDRAW, IDC_LIST_LIBRARIES, &CDlgChangeLibrary::OnNMCustomdrawListLibraries)
	ON_NOTIFY(LVN_GETINFOTIP, IDC_LIST_LIBRARIES, &CDlgChangeLibrary::OnLvnGetInfoTipListLibraries)
	ON_NOTIFY(NM_DBLCLK, IDC_LIST_LIBRARIES, &CDlgChangeLibrary::OnNMDblclkListLibraries)
	ON_NOTIFY(LVN_ODFINDITEM, IDC_LIST_LIBRARIES, &CDlgChangeLibrary::OnLvnOdfinditemListLibraries)
END_MESSAGE_MAP()


// CDlgChangeLibrary message handlers

BOOL CDlgChangeLibrary::OnInitDialog()
{
	CDialog::OnInitDialog();

	ASSERT( m_nStaffID > -1 );
	ASSERT( m_nCurrentLibrary > -1 );

	// get libraries
	appConfig.m_SQL.GetDescriptionLibraryList( &m_aLibraryList );

	// load icons
	LoadItemIcons();

	// set as list
	m_ctrlLibraries.SetView( LVS_REPORT );
	m_ctrlLibraries.SetExtendedStyle( LVS_EX_FULLROWSELECT | LVS_EX_GRIDLINES | LVS_EX_SUBITEMIMAGES | LVS_EX_INFOTIP | LVS_EX_LABELTIP );
	m_ctrlLibraries.ModifyStyle( 0, LVS_SINGLESEL );
	// set columns
	m_ctrlLibraries.InsertColumn( LIST_NAME, _T("Library"), LVCFMT_LEFT, 400, LIST_NAME );
	m_ctrlLibraries.InsertColumn( LIST_PROBLEM, _T(""), LVCFMT_CENTER,  18, LIST_PROBLEM );
	m_ctrlLibraries.InsertColumn( LIST_ILL, _T(""), LVCFMT_CENTER,  18, LIST_ILL );
	m_ctrlLibraries.InsertColumn( LIST_DIVERT, _T(""), LVCFMT_CENTER, 18, LIST_DIVERT );

	// redraw list
	m_ctrlLibraries.SetItemCountEx( m_aLibraryList.GetCount(), LVSICF_NOINVALIDATEALL | LVSICF_NOSCROLL );

	// set autosize
	m_ctrlLibraries.SetColumnWidth( LIST_NAME, LVSCW_AUTOSIZE );

	// set selected library
	for( INT nIndex=0; nIndex < m_aLibraryList.GetCount(); nIndex++ )
	{
		if( m_aLibraryList.GetAt( nIndex ).nID == m_nCurrentLibrary )
		{
			m_ctrlLibraries.SetItemState( nIndex, LVIS_SELECTED, LVIS_SELECTED );
			m_ctrlLibraries.SetSelectionMark( nIndex );
			break;
		}
	}

	// set send to
	if( m_nType == TYPE_SENDTO )
	{
		// set window title
		SetWindowText( _T("Send To...") );
		// disable at library
		if( appConfig.m_Options.bDisableAtLibrary )
			GetDlgItem( IDC_CHECK_INDICATOR )->ShowWindow( SW_HIDE );
		else
			GetDlgItem( IDC_CHECK_INDICATOR )->SetWindowText( _T("At Library") );
		// show retain status
		GetDlgItem( IDC_CHECK_RETAIN_STATUS )->ShowWindow( SW_SHOW );
	}
	else if( m_nType == TYPE_DIVERT )
	{
		// set window title
		CString szTitle;
		szTitle.Format( _T("Divert to... %s"), m_aLibraryList.GetAt( 0 ).szDescription );
		SetWindowText( szTitle );

		// disable at library
		GetDlgItem( IDC_CHECK_INDICATOR )->ShowWindow( SW_HIDE );
		GetDlgItem( IDC_CHECK_RETAIN_STATUS )->ShowWindow( SW_HIDE );
	}
	else
	{
		// show retain status
		GetDlgItem( IDC_CHECK_RETAIN_STATUS )->ShowWindow( SW_HIDE );
	}

	// update data
	UpdateData();

	return TRUE;  // return TRUE unless you set the focus to a control
	// EXCEPTION: OCX Property Pages should return FALSE
}


void CDlgChangeLibrary::OnOK()
{
	// update data
	UpdateData();

	// check library
	if( m_nNewLibrary == m_nCurrentLibrary && m_aLibraryList.GetAt( m_nSelectedLibrary ).bDiverted )
	{
		// warn
		CString szMessage;
		szMessage.Format( _T("ATTENTION: You have not selected a Library to Send to.\n\nAre you sure you want to continue?") );
		if( AfxMessageBox( szMessage, MB_YESNO ) == IDNO )
			return;
	}

	// check library diverted
	if( m_nType == TYPE_DIVERT )
	{
		// warn
		CString szMessage;
		if( m_aLibraryList.GetAt( m_nSelectedLibrary ).bDiverted )
			szMessage.Format( _T("ATTENTION: This will \"undivert\" all requests for selected Library.\n\nAre you sure you want to continue?"), m_aLibraryList.GetAt( 0 ).szDescription );			
		else
			szMessage.Format( _T("ATTENTION: This will \"divert\" all requests for this Library to %s.\n\nAre you sure you want to continue?"), m_aLibraryList.GetAt( 0 ).szDescription );			
		if( AfxMessageBox( szMessage, MB_YESNO ) == IDNO )
			return;
	}

	// set library
	m_nCurrentLibrary = m_nNewLibrary;

	// save change
	if( m_bIndicator && m_nType == TYPE_CHANGE )
	{
		// update staff
		appConfig.m_SQL.SetFieldValue( CMySQLEx::staff, _T("library_id"), m_nStaffID, m_nCurrentLibrary );
	}
	// close dialog
	CDialog::OnOK();
}


BOOL CDlgChangeLibrary::LoadItemIcons()
{
	HICON hIcon = NULL;
	HBITMAP hBitmap = NULL;
	CString szPath;
	BOOL bIconsLoaded = TRUE;

	// create image list
	m_ilImages.DeleteImageList();
	m_ilImages.Create( ICON_LIST_SIZE, ICON_LIST_SIZE, ILC_COLOR32 | ILC_MASK, 0, 1 );

	// specify path
	szPath = appConfig.m_General.szStatusIconPath;
	// get exe path
	if( szPath.Find( '\\' ) == -1 )
	{
		INT nIndex = 0;
		CString szAppPath;
		TCHAR cBuffer[MAX_PATH];

		memset( cBuffer, NULL, MAX_PATH );
		GetModuleFileName( NULL, cBuffer, MAX_PATH );
		szAppPath = cBuffer;
		nIndex = szAppPath.ReverseFind('\\');
		szAppPath = szAppPath.Left( nIndex );
		szPath.Format( _T("%s\\%s"), szAppPath, szPath );
	}
	// check for trainling backslash
	if( szPath.Right( 1 ) != _T("\\") )
		szPath += _T("\\");

	// load status icons
	hIcon = (HICON)LoadImage( NULL, szPath + _T("blank.ico"), IMAGE_ICON, ICON_LIST_SIZE, ICON_LIST_SIZE, LR_LOADFROMFILE );
	if( !hIcon )
		hIcon = (HICON)LoadIcon( AfxGetInstanceHandle(), MAKEINTRESOURCE( IDI_ICON_BLANK ));
	if( hIcon )
		m_ilImages.Add( hIcon );
	else
		bIconsLoaded = FALSE;

	hIcon = (HICON)LoadImage( NULL, szPath + _T("problem.ico"), IMAGE_ICON, ICON_LIST_SIZE, ICON_LIST_SIZE, LR_LOADFROMFILE );
	if( !hIcon )
		hIcon = (HICON)LoadIcon( AfxGetInstanceHandle(), MAKEINTRESOURCE( IDI_ICON_PROBLEM ));
	if( hIcon )
		m_ilImages.Add( hIcon );
	else
		bIconsLoaded = FALSE;

	hIcon = (HICON)LoadImage( NULL, szPath + _T("i_ill.ico"), IMAGE_ICON, ICON_LIST_SIZE, ICON_LIST_SIZE, LR_LOADFROMFILE );
	if( !hIcon )
		hIcon = (HICON)LoadIcon( AfxGetInstanceHandle(), MAKEINTRESOURCE( IDI_ICON_I_ILL ));
	if( hIcon )
		m_ilImages.Add( hIcon );
	else
		bIconsLoaded = FALSE;
	
	hIcon = (HICON)LoadImage( NULL, szPath + _T("e_ill.ico"), IMAGE_ICON, ICON_LIST_SIZE, ICON_LIST_SIZE, LR_LOADFROMFILE );
	if( !hIcon )
		hIcon = (HICON)LoadIcon( AfxGetInstanceHandle(), MAKEINTRESOURCE( IDI_ICON_E_ILL ));
	if( hIcon )
		m_ilImages.Add( hIcon );
	else
		bIconsLoaded = FALSE;

	hIcon = (HICON)LoadImage( NULL, szPath + _T("diverted.ico"), IMAGE_ICON, ICON_LIST_SIZE, ICON_LIST_SIZE, LR_LOADFROMFILE );
	if( !hIcon )
		hIcon = (HICON)LoadIcon( AfxGetInstanceHandle(), MAKEINTRESOURCE( IDI_ICON_DIVERTED ));
	if( hIcon )
		m_ilImages.Add( hIcon );
	else
		bIconsLoaded = FALSE;

	// inform user
	if( !bIconsLoaded )
		AfxMessageBox( _T("ERROR:\n\nError loading information icons."), MB_ICONSTOP );
	else
	{
		// assign image list
		m_ctrlLibraries.SetImageList( &m_ilImages, LVSIL_SMALL );
	}

	return bIconsLoaded;
}


INT CDlgChangeLibrary::GetItemImage(INT nItemId, INT nColumn)
{
	INT nImage = ICON_NONE;

	// get library
	LIBRARY_LOOKUP Library;
	Library = m_aLibraryList.GetAt( nItemId );

	// set flags
	BOOL bProblemLibrary = Library.nType & ID_PROBLEM_LIBRARY ? TRUE : FALSE;
	BOOL bInternalILLLibrary = Library.nType & ID_INTERNAL_ILL_LIBRARY ? TRUE : FALSE;
	BOOL bExternalILLLibrary = Library.nType & ID_EXTERNAL_ILL_LIBRARY ? TRUE : FALSE;

	// check column
	switch( nColumn )
	{
		// set info
		case LIST_PROBLEM:
			if( bProblemLibrary )
				nImage = ICON_LIBRARY_PROBLEM;
			else
				nImage = ICON_NONE;
			break;
		// set info
		case LIST_ILL:
			if( bInternalILLLibrary )
				nImage = ICON_LIBRARY_LENDING_ILL;
			else if( bExternalILLLibrary )
				nImage = ICON_LIBRARY_BORROWING_ILL;
			else
				nImage = ICON_NONE;
			break;
		// set info
		case LIST_DIVERT:
			if( Library.bDiverted )
				nImage = ICON_LIBRARY_DIVERTED;
			else
				nImage = ICON_NONE;
			break;
		// do default
		default:
			nImage = ICON_NONE;
			break;
	}
	// return image
	return nImage;
}


BOOL CDlgChangeLibrary::GetItemHighlight(LONG nItemId, INT nColumn, LPCOLORREF pclrText, LPCOLORREF pclrTextBk, PINT pnWeight, PBOOL pbItalic, PBOOL pbUnderline)
{
	// check id
	if( nItemId > m_aLibraryList.GetUpperBound() )
		return FALSE;

	// get library
	LIBRARY_LOOKUP Library;
	Library = m_aLibraryList.GetAt( nItemId );

	// set flags
	BOOL bProblemLibrary = Library.nType & ID_PROBLEM_LIBRARY ? TRUE : FALSE;
	BOOL bInternalILLLibrary = Library.nType & ID_INTERNAL_ILL_LIBRARY ? TRUE : FALSE;
	BOOL bExternalILLLibrary = Library.nType & ID_EXTERNAL_ILL_LIBRARY ? TRUE : FALSE;

	// set current library background
	if( nColumn == LIST_NAME )
	{
		if( Library.nID == m_nCurrentLibrary )
			*pclrTextBk = appConfig.m_Colors.dwDuplicateHighlight;
		else if( Library.nUserListed )
			*pclrTextBk = appConfig.m_Colors.dwLibraryListed;
	}

	// return
	return TRUE;
}


void CDlgChangeLibrary::OnLvnItemchangedListLibraries(NMHDR *pNMHDR, LRESULT *pResult)
{
	// get item
	LPNMLISTVIEW pNMLV = reinterpret_cast<LPNMLISTVIEW>(pNMHDR);

    // Which item number?
    INT nItemId = pNMLV->iItem;
	if( nItemId < 0 )
	{
		// no selection
		m_nNewLibrary = -1;

		// disable buttons
		GetDlgItem( IDOK )->EnableWindow( FALSE );

		//return result
		*pResult = 0;
		return;
	}

	// get library
	ASSERT( nItemId <= m_aLibraryList.GetCount() );
	LIBRARY_LOOKUP Library;
	Library = m_aLibraryList.GetAt( nItemId );

	// set selected library
	m_nSelectedLibrary = nItemId;

	// set current id
	m_nNewLibrary = Library.nID;

	// set OK button text
	if( m_nType == TYPE_DIVERT )
	{
		if( m_aLibraryList.GetAt( m_nSelectedLibrary ).bDiverted )
			GetDlgItem( IDOK )->SetWindowText( _T("Undivert") );
		else
			GetDlgItem( IDOK )->SetWindowText( _T("Divert") );
		// enable buttons
		if( m_nNewLibrary != 0 )
			GetDlgItem( IDOK )->EnableWindow();
		else
			GetDlgItem( IDOK )->EnableWindow( FALSE );
	}
	else
	{
		// enable buttons
		if( m_nNewLibrary != m_nCurrentLibrary )
			GetDlgItem( IDOK )->EnableWindow();
		else
			GetDlgItem( IDOK )->EnableWindow( FALSE );
	}

	//return result
	*pResult = 0;
}


void CDlgChangeLibrary::OnLvnGetdispinfoListLibraries(NMHDR *pNMHDR, LRESULT *pResult)
{
	// get item
	NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);
	// set default
	*pResult = 0;

    // Create a pointer to the item
    LV_ITEM* pItem = &(pDispInfo)->item;

    // Which item number?
    INT nItemId = pItem->iItem;

	// get library
	ASSERT( nItemId <= m_aLibraryList.GetCount() );
	LIBRARY_LOOKUP Library;
	Library = m_aLibraryList.GetAt( nItemId );

	// Does the list need text information?
	if( pItem->mask & LVIF_TEXT )
	{
		//TRACE( _T("SubItem = %d\n"), pItem->iSubItem );

		// set text
		CString szText;
		// set item id
		switch( pItem->iSubItem )		
		{
		case LIST_NAME:
			szText.Format(_T("%s"), Library.szDescription );
			break;
		}
		//Copy the text to the LV_ITEM structure
		//Maximum number of characters is in pItem->cchTextMax
		lstrcpyn( pItem->pszText, szText, pItem->cchTextMax );
	}

	// Does the list need image information?
	if( pItem->mask & LVIF_IMAGE ) 
	{
		// insert image
		INT nImage = GetItemImage( nItemId, pItem->iSubItem );
		// set image
		if( nImage >= 0 )
			pItem->iImage = nImage;
	}

	// return
	*pResult = CDRF_DODEFAULT;
}


void CDlgChangeLibrary::OnNMCustomdrawListLibraries(NMHDR *pNMHDR, LRESULT *pResult)
{
	// get item
	LPNMLVCUSTOMDRAW pLVCD = reinterpret_cast<LPNMLVCUSTOMDRAW>(pNMHDR);	
	// set default
	*pResult = CDRF_DODEFAULT;

	switch( pLVCD->nmcd.dwDrawStage )
	{
		case CDDS_PREPAINT:
			{
				// set to notify draw item
				*pResult |= CDRF_NOTIFYITEMDRAW;
			}
			break;

		case CDDS_ITEMPREPAINT:
			{
				// set to notify pre paint sub item
				*pResult |= CDRF_NOTIFYSUBITEMDRAW;
			}
			break;

		case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
			{
				INT nItemId = static_cast<int>( pLVCD->nmcd.dwItemSpec );
				INT nWeight = FW_NORMAL;
				BOOL bItalic = FALSE;
				BOOL bUnderline = FALSE;
				COLORREF clrText = RGB( 0x00, 0x00, 0x00 ), clrTextBk = RGB( 0xff, 0xff, 0xff );

				// default colors
				pLVCD->clrText = clrText;
				pLVCD->clrTextBk = clrTextBk;

				// set colors
				if( GetItemHighlight( nItemId, pLVCD->iSubItem, &clrText, &clrTextBk, &nWeight, &bItalic, &bUnderline ))
				{
					pLVCD->clrText = clrText;
					pLVCD->clrTextBk = clrTextBk;
				}
				// check for bold				
				if(( nWeight != FW_NORMAL ) || bItalic || bUnderline )
				{
					CFont fntFont;
					LOGFONT lfFont;
					m_ctrlLibraries.GetFont()->GetLogFont( &lfFont );
					// Set font style
					lfFont.lfWeight = nWeight;
					lfFont.lfItalic = bItalic;
					lfFont.lfUnderline = bUnderline;
					// Create a new font
					fntFont.CreateFontIndirect( &lfFont );
					// Select font
					SelectObject( pLVCD->nmcd.hdc, fntFont );
					// return new font
					*pResult |= CDRF_NEWFONT;
				}

				// check for tab sort
				if( pLVCD->iSubItem == m_nCurrentSort )
					pLVCD->clrTextBk = appConfig.m_Colors.dwSortHighlight;

				// set result for post paint
				if( pLVCD->nmcd.uItemState & CDIS_FOCUS )
					*pResult |= CDRF_NOTIFYPOSTPAINT;
			}
			break;

		case CDDS_ITEMPOSTPAINT | CDDS_SUBITEM:
			{
				// get image and draw it
				INT nItemId = static_cast<int>( pLVCD->nmcd.dwItemSpec );
				INT nImage = GetItemImage( nItemId, pLVCD->iSubItem );
				if( nImage >= 0 )
				{
					CRect rcIcon;
					CDC*  pDC = CDC::FromHandle( pLVCD->nmcd.hdc );
					// Get the rect that holds the item's icon.
					m_ctrlLibraries.GetSubItemRect( nItemId, pLVCD->iSubItem, LVIR_ICON, rcIcon );					
					// Draw the icon.					
					m_ilImages.Draw( pDC, nImage, rcIcon.TopLeft(), ILD_TRANSPARENT );					
					// skip default
					*pResult = CDRF_SKIPDEFAULT;
				}
			}
			break;
	}
}


void CDlgChangeLibrary::OnLvnGetInfoTipListLibraries(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMLVGETINFOTIP pGetInfoTip = reinterpret_cast<LPNMLVGETINFOTIP>(pNMHDR);

    // Which item number?
    INT nItemId = pGetInfoTip->iItem;

	// get library
	ASSERT( nItemId <= m_aLibraryList.GetCount() );
	LIBRARY_LOOKUP Library;
	Library = m_aLibraryList.GetAt( nItemId );

	// set flags
	BOOL bProblemLibrary = Library.nType & ID_PROBLEM_LIBRARY ? TRUE : FALSE;
	BOOL bInternalILLLibrary = Library.nType & ID_INTERNAL_ILL_LIBRARY ? TRUE : FALSE;
	BOOL bExternalILLLibrary = Library.nType & ID_EXTERNAL_ILL_LIBRARY ? TRUE : FALSE;

	CString szText;
	//szText.Format(_T("%s"), Library.szName);

	// add other information
	if( bProblemLibrary )
		szText += _T("Problem Library\n");
	if( bInternalILLLibrary )
		szText += _T("Internal ILL Library\n");
	if( bExternalILLLibrary )
		szText += _T("External ILL Library\n");
	if( Library.bDiverted )
		szText += _T("Requests are currently being diverted\n");
	if( Library.nID == m_nCurrentLibrary )
		szText += _T("Current Library\n");
	else if( !Library.nUserListed )
		szText += _T("Library is not user listed\n");

	// set tooltip
	_tcscpy_s( pGetInfoTip->pszText, INFOTIPSIZE, (LPCTSTR)szText );

	// return
	*pResult = 0;
}


void CDlgChangeLibrary::OnNMDblclkListLibraries(NMHDR *pNMHDR, LRESULT *pResult)
{
	LPNMITEMACTIVATE pNMItemActivate = reinterpret_cast<LPNMITEMACTIVATE>(pNMHDR);
	// TODO: Add your control notification handler code here
	*pResult = 0;
	// do ok;
	OnOK();
}


void CDlgChangeLibrary::OnLvnOdfinditemListLibraries(NMHDR *pNMHDR, LRESULT *pResult)
{
	// pNMHDR has information about the item we should find
    // In pResult we should save which item that should be selected
	LPNMLVFINDITEM pFindInfo = reinterpret_cast<LPNMLVFINDITEM>(pNMHDR);

    /*
		pFindInfo->iStart is from which item we should search.
		We search to bottom, and then restart at top and will stop
		at pFindInfo->iStart, unless we find an item that match
	*/

    // Set the default return value to -1 that means we didn't find any match.
    *pResult = -1;

    //Is search NOT based on string?
    if(( pFindInfo->lvfi.flags & LVFI_STRING ) == 0 )
    {
        //This will probably never happend...
        return;
    }

    //This is the string we search for
	CString szSearch = pFindInfo->lvfi.psz;

	//TRACE(_T("Find %s on %d\n"), szSearch, m_nCurrentSort);

    INT startPos = pFindInfo->iStart;
    //Is startPos outside the list (happens if last item is selected)
    if( startPos >= m_ctrlLibraries.GetItemCount() )
        startPos = 0;

	LIBRARY_LOOKUP Library;
	INT currentPos = startPos;
	INT nColumn = m_nCurrentSort;

	// search
    do
    {
		// get record
		Library = m_aLibraryList.GetAt( currentPos );

		// find in column
		switch( nColumn )
		{
		case LIST_NAME:
			{
				// search the library column
				if( szSearch.CompareNoCase( Library.szName.Left( szSearch.GetLength() )) == 0 )
				{
					//Select this item and stop search.
					*pResult = currentPos;
					return;
				}
			}
			break;
		default:
			// search the library column
			if( szSearch.CompareNoCase( Library.szName.Left( szSearch.GetLength() )) == 0 )
			{
				//Select this item and stop search.
				*pResult = currentPos;
				return;
			}
		}

        //Go to next item
        currentPos++;

        //Need to restart at top?
        if( currentPos >= m_ctrlLibraries.GetItemCount() )
            currentPos = 0;
    }
    //Stop if back to start
	while( currentPos != startPos );
}
